﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;


namespace TouShuShenQi.BlazorCore.Crawler
{
    public class SimpleCrawler:ICrawler
    {
        /// <summary>
        /// 爬虫启动事件
        /// </summary>
        public event EventHandler<OnStartEventArgs> OnStart;
        /// <summary>
        /// 爬虫完成事件
        /// </summary>
        public event EventHandler<OnCompletedEventArgs> OnCompleted;
        /// <summary>
        /// 爬虫出错事件
        /// </summary>
        public event EventHandler<OnErrorEventArgs> OnError;
        /// <summary>
        /// 定义Cookie容器
        /// </summary>
        public CookieContainer CookiesContainer { get; set; }

        /// <summary>
        /// 爬行地址
        /// </summary>
        public Uri CrawlerUrl  { get; set; }

        /// <summary>
        /// 超时时间（毫秒）
        /// </summary>
        public int Timeout { get; set; } = 5*1000;

        /// <summary>
        /// 代理地址127.0.0.1:1080
        /// </summary>
        public string ProxyAddress { get; set; }
 
        /// <summary>
        /// 蜘蛛的请求方式
        /// </summary>
        public string Method { get; set; } = "GET";
        /// <summary>
        /// 用户请求模拟
        /// </summary>
        public string UserAgent { get; set; } = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";


        /// <summary>
        /// 蜘蛛的请求类
        /// </summary>
        public HttpWebRequest CrawlerRequest { get; set; }

        /// <summary>
        /// 构造
        /// </summary>
        public SimpleCrawler() { }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="CrawlerUrl"></param>
        public SimpleCrawler(string crawlerUrl,string proxyAddress = "",string method ="GET",string userAgent ="",int timeout = 5000,  CookieContainer cookiesContainer = null) 
        {
            this.CrawlerUrl = new Uri(crawlerUrl) ;
            this.ProxyAddress = proxyAddress;
            this.CookiesContainer = cookiesContainer;
            this.Method = method;
            this.Timeout = timeout;

            if (!string.IsNullOrWhiteSpace(userAgent))
            {
                this.UserAgent = userAgent;
            }
    
        }

        /// <summary>
        /// 异步开始爬行
        /// </summary>
        /// <returns></returns>
        public async Task<string> StartAsync()
        {
            return await Task.Run(() =>
            {
                return Start();
            });
        }

        /// <summary>
        /// 创建请求类
        /// </summary>
        /// <returns></returns>
        private HttpWebRequest CreateWebRequest()
        {
            CrawlerRequest = (HttpWebRequest)WebRequest.Create(this.CrawlerUrl);
            CrawlerRequest.Accept = "*/*";
            CrawlerRequest.ServicePoint.Expect100Continue = false;//加快载入速度
            CrawlerRequest.ServicePoint.UseNagleAlgorithm = false;//禁止Nagle算法加快载入速度
            CrawlerRequest.AllowWriteStreamBuffering = false;//禁止缓冲加快载入速度
            CrawlerRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");//定义gzip压缩页面支持
            CrawlerRequest.ContentType = "application/x-www-form-urlencoded";//定义文档类型及编码
            CrawlerRequest.AllowAutoRedirect = false;//禁止自动跳转
            CrawlerRequest.KeepAlive = true;//启用长连接


            //设置User-Agent，伪装成Google Chrome浏览器
            CrawlerRequest.UserAgent = this.UserAgent;
            CrawlerRequest.Timeout = this.Timeout;//定义请求超时时间为5秒
            CrawlerRequest.Method = this.Method;//定义请求方式为GET
            CrawlerRequest.ServicePoint.ConnectionLimit = int.MaxValue;//定义最大连接数

            //附加Cookie容器
            if (this.CookiesContainer != null)
            {
                CrawlerRequest.CookieContainer = this.CookiesContainer;
            }

            //设置代理服务器IP，伪装请求地址                                                    
            if (!string.IsNullOrWhiteSpace(this.ProxyAddress))
            {
                CrawlerRequest.Proxy = new WebProxy(this.ProxyAddress);
            }
            return CrawlerRequest;
        }




        /// <summary>
        /// 开始爬行
        /// </summary>
        /// <returns></returns>
        public string Start()
        {

            var pageSource = string.Empty;
            try
            {
                if (this.OnStart != null)
                {
                    this.OnStart(this, new OnStartEventArgs(this.CrawlerUrl));
                }

                var watch = new Stopwatch();
                watch.Start();

                //获取请求响应
                var request = CreateWebRequest();
                using (var response = (HttpWebResponse)request.GetResponse())
                {
                    //将Cookie加入容器，保存登录状态
                    foreach (Cookie cookie in response.Cookies)
                    {
                        this.CookiesContainer.Add(cookie);
                    }

                    if (response.ContentEncoding.ToLower().Contains("gzip"))//解压
                    {
                        using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))
                        {
                            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                            {
                                pageSource = reader.ReadToEnd();
                            }
                        }
                    }
                    else if (response.ContentEncoding.ToLower().Contains("deflate"))//解压
                    {
                        using (DeflateStream stream = new DeflateStream(response.GetResponseStream(), CompressionMode.Decompress))
                        {
                            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                            {
                                pageSource = reader.ReadToEnd();
                            }
                        }
                    }
                    else
                    {
                        using (Stream stream = response.GetResponseStream())//原始
                        {
                            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                            {
                                pageSource = reader.ReadToEnd();
                            }
                        }
                    }
                }
                request.Abort();
                watch.Stop();
                var threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;//获取当前任务线程ID
                var milliseconds = watch.ElapsedMilliseconds;//获取请求执行时间
                if (this.OnCompleted != null)
                {
                    this.OnCompleted(this, new OnCompletedEventArgs(this.CrawlerUrl, threadId, milliseconds, pageSource));
                }
            }
            catch (Exception ex)
            {
                if (this.OnError != null)
                {
                    this.OnError(this, new OnErrorEventArgs(this.CrawlerUrl, ex));
                }
            }
            return pageSource;

        }
 


    }


}
